﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;

namespace InnerProduct
{
    public class ColorPickr : Control
    {
        bool colorGuard = false;
        public ColorPickr()
        {
            this.DefaultStyleKey = typeof(ColorPickr);
            this.AddHandler(TextBox.KeyDownEvent, new KeyEventHandler(TextBox_KeyDown), false);
        }
 
        private void TextBox_KeyDown(object sender, RoutedEventArgs e)
        {
            TextBox textBox = e.OriginalSource as TextBox;
            KeyEventArgs args = e as KeyEventArgs;
            if (args != null && args.Key == Key.Enter && textBox != null)
            {
                BindingExpression binding = textBox.GetBindingExpression(TextBox.TextProperty);
                if (binding != null)
                {
                    binding.UpdateSource();
                }
            }
        }

        #region Color (DependencyProperty)

        /// <summary>
        /// Rgb version of current pickr color
        /// </summary>
        public Color Color
        {
            get { return (Color)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }
        public static readonly DependencyProperty ColorProperty =
            DependencyProperty.Register("Color", typeof(Color), typeof(ColorPickr),
            new PropertyMetadata(new Color() {R = 255, G = 255, B = 255, A = 255}, new PropertyChangedCallback(OnColorChanged)));

        private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ColorPickr)d).OnColorChanged(e);
        }

        protected virtual void OnColorChanged(DependencyPropertyChangedEventArgs e)
        {
            Color c = (Color)e.NewValue;
            if (!colorGuard)
            {
                colorGuard = true;
                ColorHSV = new ColorHSV() { Color = c };
            }
            else
            {
                colorGuard = false;
            }
            R = c.R;
            G = c.G;
            B = c.B;
            A = c.A;
        }

        #endregion

        #region R (DependencyProperty)

        /// <summary>
        /// Red color component
        /// </summary>
        public byte R
        {
            get { return (byte)GetValue(RProperty); }
            set { SetValue(RProperty, value); }
        }
        public static readonly DependencyProperty RProperty =
            DependencyProperty.Register("R", typeof(byte), typeof(ColorPickr),
            new PropertyMetadata((byte)255, new PropertyChangedCallback(OnRChanged)));

        private static void OnRChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ColorPickr)d).OnRChanged(e);
        }

        protected virtual void OnRChanged(DependencyPropertyChangedEventArgs e)
        {
            Color = new Color() { R = (byte)e.NewValue, G = Color.G, B = Color.B, A = Color.A };
        }

        #endregion

        #region G (DependencyProperty)

        /// <summary>
        /// Green color component
        /// </summary>
        public byte G
        {
            get { return (byte)GetValue(GProperty); }
            set { SetValue(GProperty, value); }
        }
        public static readonly DependencyProperty GProperty =
            DependencyProperty.Register("G", typeof(byte), typeof(ColorPickr),
            new PropertyMetadata((byte)255, new PropertyChangedCallback(OnGChanged)));

        private static void OnGChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ColorPickr)d).OnGChanged(e);
        }

        protected virtual void OnGChanged(DependencyPropertyChangedEventArgs e)
        {
            Color = new Color() { G = (byte)e.NewValue, R = Color.R, B = Color.B, A = Color.A };
        }

        #endregion

        #region B (DependencyProperty)

        /// <summary>
        /// Blue color component
        /// </summary>
        public byte B
        {
            get { return (byte)GetValue(BProperty); }
            set { SetValue(BProperty, value); }
        }
        public static readonly DependencyProperty BProperty =
            DependencyProperty.Register("B", typeof(byte), typeof(ColorPickr),
            new PropertyMetadata((byte)255, new PropertyChangedCallback(OnBChanged)));

        private static void OnBChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ColorPickr)d).OnBChanged(e);
        }

        protected virtual void OnBChanged(DependencyPropertyChangedEventArgs e)
        {
            Color = new Color() { B = (byte)e.NewValue, R = Color.R, G = Color.G, A = Color.A };
        }

        #endregion

        #region A (DependencyProperty)

        /// <summary>
        /// Alpha color component
        /// </summary>
        public byte A
        {
            get { return (byte)GetValue(AProperty); }
            set { SetValue(AProperty, value); }
        }
        public static readonly DependencyProperty AProperty =
            DependencyProperty.Register("A", typeof(byte), typeof(ColorPickr),
            new PropertyMetadata((byte)255, new PropertyChangedCallback(OnAChanged)));

        private static void OnAChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ColorPickr)d).OnAChanged(e);
        }

        protected virtual void OnAChanged(DependencyPropertyChangedEventArgs e)
        {
            Color = new Color() { A = (byte)e.NewValue, R = Color.R, B = Color.B, G = Color.G };
        }

        #endregion

        #region ColorHSV (DependencyProperty)

        /// <summary>
        /// HSV version of current color
        /// </summary>
        public ColorHSV ColorHSV
        {
            get { return (ColorHSV)GetValue(ColorHSVProperty); }
            set { SetValue(ColorHSVProperty, value); }
        }
        public static readonly DependencyProperty ColorHSVProperty =
            DependencyProperty.Register("ColorHSV", typeof(ColorHSV), typeof(ColorPickr),
            new PropertyMetadata(new ColorHSV(0,0,1.0), new PropertyChangedCallback(OnColorHSVChanged)));

        private static void OnColorHSVChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ColorPickr)d).OnColorHSVChanged(e);
        }

        protected virtual void OnColorHSVChanged(DependencyPropertyChangedEventArgs e)
        {
            ColorHSV hsv = (ColorHSV)e.NewValue;
            if (!colorGuard)
            {
                colorGuard = true;
                Color = hsv.Color;
            }
            else
            {
                colorGuard = false;
            }
            H = hsv.H;
            S = hsv.S;
            V = hsv.V;
        }

        #endregion

        #region H (DependencyProperty)

        /// <summary>
        /// Hue component. Valid range 0..1
        /// </summary>
        public double H
        {
            get { return (double)GetValue(HProperty); }
            set { SetValue(HProperty, value); }
        }
        public static readonly DependencyProperty HProperty =
            DependencyProperty.Register("H", typeof(double), typeof(ColorPickr),
            new PropertyMetadata(0.0, new PropertyChangedCallback(OnHChanged)));

        private static void OnHChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ColorPickr)d).OnHChanged(e);
        }

        protected virtual void OnHChanged(DependencyPropertyChangedEventArgs e)
        {
            ColorHSV = new ColorHSV((double)e.NewValue, ColorHSV.S, ColorHSV.V) {A = A};
        }

        #endregion

        #region S (DependencyProperty)

        /// <summary>
        /// Saturation component. Valid range 0..1
        /// </summary>
        public double S
        {
            get { return (double)GetValue(SProperty); }
            set { SetValue(SProperty, value); }
        }
        public static readonly DependencyProperty SProperty =
            DependencyProperty.Register("S", typeof(double), typeof(ColorPickr),
            new PropertyMetadata(0.0, new PropertyChangedCallback(OnSChanged)));

        private static void OnSChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ColorPickr)d).OnSChanged(e);
        }

        protected virtual void OnSChanged(DependencyPropertyChangedEventArgs e)
        {
            ColorHSV = new ColorHSV(ColorHSV.H, (double)e.NewValue, ColorHSV.V) { A = Color.A };
        }

        #endregion

        #region V (DependencyProperty)

        /// <summary>
        /// Value component. Valid range 0..1
        /// </summary>
        public double V
        {
            get { return (double)GetValue(VProperty); }
            set { SetValue(VProperty, value); }
        }
        public static readonly DependencyProperty VProperty =
            DependencyProperty.Register("V", typeof(double), typeof(ColorPickr),
            new PropertyMetadata(1.0, new PropertyChangedCallback(OnVChanged)));

        private static void OnVChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ColorPickr)d).OnVChanged(e);
        }

        protected virtual void OnVChanged(DependencyPropertyChangedEventArgs e)
        {
            ColorHSV = new ColorHSV(ColorHSV.H, ColorHSV.S, (double)e.NewValue) { A = Color.A };
        }

        #endregion
    }

    #region ValueConverters

    //Color to hex string
    public class ColorToHex : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Color rgb = (Color)value;
            return string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", rgb.A, rgb.R, rgb.G, rgb.B);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class ByteToString : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return ((Byte)value).ToString();
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try
            {
                return System.Convert.ToByte((string)value);
            }
            catch
            {
                return DependencyProperty.UnsetValue;
            }
        }
    }

    public class ColorToBrush : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return new SolidColorBrush((Color) value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return ((SolidColorBrush)(value)).Color;
        }
    }

    #endregion
}
